package com.za.plugin.transfer.form;


import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlSelectQueryBlock;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlASTVisitorAdapter;

import java.util.HashMap;
import java.util.List;

/**
 * 达梦 group by 后面不能跟随别名，必须使用原来真实的名称，即使是计算表达式
 * 这个代码不是很重要，只要 sql 不报错就行，但想要完全处理好，是比较困难的
 * <p>
 * <p>
 * 达梦不支持 having 后面使用别名。
 * 把 having 后的别名替换为原来的样子, having 可能是在嵌套子 select 查询里。
 */
public class GroupByAliasFormTransfer implements FormTransfer {

    public static final String GROUP_BY = " group by ";

    @Override
    public boolean isSupport(String sql) {
        return sql.toLowerCase().replaceAll("\\s+group\\s+by\\s+", " group by ")
                .contains(" group by ");
    }

    @Override
    public String transfer(String sql) {
        return truncateAlias(sql);
    }

    private static String truncateAlias(String sql) {
        MySqlStatementParser parser = new MySqlStatementParser(sql);
        SQLStatement sqlStatement = parser.parseStatement();
        sqlStatement.accept(new MySqlASTVisitorAdapter() {
            @Override
            public boolean visit(MySqlSelectQueryBlock queryBlock) {
                List<SQLSelectItem> selectList = queryBlock.getSelectList();
                HashMap<String, SQLExpr> map = new HashMap<>();
                for (SQLSelectItem item : selectList) {
                    if (item.getAlias() != null) {
                        map.put(item.getAlias().replace("\"",""), item.getExpr());
                    }
                }
                // 把 Group by 后面的别名替换为实际值
                if (queryBlock.getGroupBy() != null) {
                    List<SQLExpr> items = queryBlock.getGroupBy().getItems();
                    if (!items.isEmpty()) {
                        for (int i = 0; i < items.size(); i++) {
                            String alias = SQLUtils.toMySqlString(items.get(i));
                            if (map.containsKey(alias)) {
                                items.set(i, map.get(alias));
                            }
                        }
                    }
                }
                // 把 having 后面的别名替换为实际值  有 ? 的实际值不要也可以
                if (queryBlock.getGroupBy() != null && queryBlock.getGroupBy().getHaving() != null) {
                    queryBlock.getGroupBy().getHaving().accept(new MySqlASTVisitorAdapter() {
                        @Override
                        public boolean visit(SQLBinaryOpExpr expr) {
                            if (map.containsKey(SQLUtils.toMySqlString(expr.getLeft()))) {
                                SQLExpr left = map.get(SQLUtils.toMySqlString(expr.getLeft()));
                                if (!SQLUtils.toMySqlString(left).contains("?")){
                                    expr.setLeft(left);
                                }
                            } else if (map.containsKey(SQLUtils.toMySqlString(expr.getRight()))) {
                                SQLExpr right = map.get(SQLUtils.toMySqlString(expr.getRight()));
                                if (!SQLUtils.toMySqlString(right).contains("?")){
                                    expr.setRight(right);
                                }
                            }
                            return super.visit(expr);
                        }
                        @Override
                        public boolean visit(SQLMethodInvokeExpr expr) {
                            expr.getParameters().forEach(param -> {
                                if (map.containsKey(SQLUtils.toMySqlString(param))) {
                                    param.accept(new MySqlASTVisitorAdapter() {
                                        @Override
                                        public boolean visit(SQLIdentifierExpr expr) {
                                            if (map.containsKey(expr.getName())) {
                                                expr.setName(SQLUtils.toMySqlString(map.get(expr.getName())));
                                            }
                                            return super.visit(expr);
                                        }
                                    });
                                }
                            });
                            return super.visit(expr);
                        }
                    });
                }
                return super.visit(queryBlock);
            }
        });


//        SQLSelectStatement sqlSelectStatement = (SQLSelectStatement) parser.parseStatement();
//        SQLSelectQuery query = sqlSelectStatement.getSelect().getQuery();
//        query.accept(
//        );
        sql = SQLUtils.toMySqlString(sqlStatement);
        return sql;
    }

    public static void main(String[] args) {
        String sql = "select a.t tt from (select c.a t,c.g dd from c group by t desc having t > 0 ) a group by tt desc";
        System.out.println(truncateAlias(sql));
    }


    private int getWordOrderIdx(String sql, String pattern, int order) {
        int idx = 0, preIdx = 0;
        for (int i = 0; i < order; i++) {
            idx = sql.indexOf(pattern, preIdx);
            preIdx = idx;
        }
        return idx;
    }

    private String swap(String sql, String groupByProperty, String s) {
        int idx = sql.indexOf("group by");
        StringBuilder sb = new StringBuilder();
        int i = sql.indexOf(groupByProperty, idx);
        return sb.append(sql, 0, i).append(s).append(sql.substring(i + groupByProperty.length())).toString();
    }

    //        int count = StrUtil.getCount(sql, GROUP_BY);
//        for (int order = 1; order <= count; order++) {
//            int wordOrderIdx = getWordOrderIdx(sql, GROUP_BY, order);
//            String subSelect = SqlUtil.getValidSelect(sql, wordOrderIdx);
//            String subSelectCopy = new String(subSelect);
//            if (subSelect.contains(GROUP_BY)) {
//                List<String> groupByProperties = SqlUtil.getGroupByProperties(subSelect);
//                Map<String, String> selectProperties = SqlUtil.getSelectProperties(subSelect, 0);
//                for (String groupByProperty : groupByProperties) {
//                    if (groupByProperty.contains(".")) {
//                        continue;
//                    }
//                    if (selectProperties.containsKey(groupByProperty)) {
//                        subSelect = swap(subSelect, groupByProperty, selectProperties.get(groupByProperty));
//                    }
//                }
//                sql = sql.replace(subSelectCopy, subSelect);
////                int index = sql.indexOf("select");
////                sql = sql.substring(0, index) + " select " + "  "
////                        + sql.substring(index + "select".length());
//            }
//            return sql;
//        }
}
